package com.cq.hd.order.factory.orderSettle;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.entity.hf.HfTradeMarketPay;
import com.cq.hd.common.enums.biz.OrderSettleBillTradeStateEnum;
import com.cq.hd.common.enums.biz.OrderSettleBillTradeTypeEnum;
import com.cq.hd.common.response.Throw;
import com.cq.hd.common.utils.BeanUtils;
import com.cq.hd.common.utils.GenerateUtil;
import com.cq.hd.common.utils.LocalDateUtil;
import com.cq.hd.member.api.TbBusinessApi;
import com.cq.hd.member.api.dto.BusinessSubSubsidyAmtDto;
import com.cq.hd.order.api.vo.OrderSettleBillVo;
import com.cq.hd.order.config.LockUtils;
import com.cq.hd.order.mapper.TbOrderSettleBillMapper;
import com.cq.hd.order.po.TbOrderSettleBillPo;
import com.cq.hd.system.api.HfApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.time.LocalDateTime;

@Component
@Slf4j
public class MerchantSubsidyOrderSettleBillHandler extends AbstractOrderSettleBillHandler {

    @Autowired
    private TbOrderSettleBillMapper orderSettleBillMapper;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private TbBusinessApi businessApi;

    @Autowired
    private HfApi hfApi;

    @Override
    protected Integer getType() {
        return OrderSettleBillTradeTypeEnum.SUBSIDY_AMT.getValue();
    }

    @Override
    public Boolean transactAmt(OrderSettleBillVo orderSettleBillVo) {
        Long id = orderSettleBillVo.getId();

        String lockKey = MessageFormat.format(Constant.LOCK_FORMAT, "transactSubsidyAmt:" + id);
        try {
            LockUtils.blockLock(lockKey, Constant.AUTO_UNLOCK_SECOND);

            TbOrderSettleBillPo tbOrderSettleBillPo = orderSettleBillMapper.selectById(id);
            if (OrderSettleBillTradeStateEnum.SUCCESS.getValue().equals(tbOrderSettleBillPo.getTradeState())) {
                log.info("订单结算商品补贴已处理成功，orderSettleBillId：{}", id);
                return true;
            }

            LocalDateTime nowLocalDateTime = LocalDateUtil.getNowLocalDateTime();
            String yyyyMMdd = LocalDateUtil.toLocalDateToString(nowLocalDateTime.toLocalDate(), "yyyyMMdd");
            String reqSeqId = LocalDateUtil.toLocalDateTimeToString(nowLocalDateTime, "yyyyMMddHHmmss") + GenerateUtil.getRandomNum(5);

            HfTradeMarketPay hfTradeMarketPay = new HfTradeMarketPay();
            hfTradeMarketPay.setReqDate(yyyyMMdd);
            hfTradeMarketPay.setReqSeqId(reqSeqId);
            hfTradeMarketPay.setOrgReqDate(orderSettleBillVo.getReqDate());
            hfTradeMarketPay.setOrgReqSeqId(orderSettleBillVo.getReqSeqId());
            JSONObject queryJSONObject = hfApi.tradeMarketTransferQuery(hfTradeMarketPay).unpack();
            if (queryJSONObject != null) {
                JSONObject data = queryJSONObject.getJSONObject("data");
                String respCode = data.getString("resp_code");
                if ("00000000".equals(respCode)) {
                    // 交易状态 P:处理中；S：成功；F：失败
                    String transStat = data.getString("trans_status");
                    // 手续费金额
                    String feeAmt = data.getString("fee_amt");
                    // 技术服务费金额
                    String invoiceAmt = data.getString("invoice_amt");

                    // 记录手续费
                    orderSettleBillVo.setFeeAmt(new BigDecimal(feeAmt).add(new BigDecimal(invoiceAmt)));
                    if ("S".equals(transStat)) {
                        orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.SUCCESS.getValue());
                    } else if ("P".equals(transStat)) {
                        orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.PROCESSING.getValue());
                    } else if ("F".equals(transStat)) {
                        orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.FAIL.getValue());
                        orderSettleBillVo.setTradeFailReason(JSON.toJSONString(data));
                    } else {
                        orderSettleBillVo.setTradeFailReason(JSON.toJSONString(data));
                    }

                    // 如果失败，则重新调用定制补贴转账接口（给商户分补贴），并更新订单结算记录状态
                    if (OrderSettleBillTradeStateEnum.FAIL.getValue().equals(orderSettleBillVo.getTradeState())) {
                        // 如果是重新调用余额支付接口，则请求日期和请求流水号需要用最新的
                        orderSettleBillVo.setReqDate(yyyyMMdd);
                        orderSettleBillVo.setReqSeqId(reqSeqId);

                        // 调用定制补贴转账接口（给商户分补贴）
                        hfTradeMarketPay = new HfTradeMarketPay();
                        hfTradeMarketPay.setReqDate(orderSettleBillVo.getReqDate());
                        hfTradeMarketPay.setReqSeqId(orderSettleBillVo.getReqSeqId());
                        hfTradeMarketPay.setInHfId(orderSettleBillVo.getInHfId());
                        hfTradeMarketPay.setInHfAcctId(orderSettleBillVo.getInHfAcctId());
                        hfTradeMarketPay.setOutHfId(orderSettleBillVo.getOutHfId());
                        hfTradeMarketPay.setTransAmt(orderSettleBillVo.getReceiveAmt().toString());
                        JSONObject jsonObject = hfApi.tradeMarketTransferPay(hfTradeMarketPay).unpack();
                        if (jsonObject != null) {
                            data = jsonObject.getJSONObject("data");
                            // 交易状态 P:处理中；S：成功；F：失败
                            transStat = data.getString("trans_status");
                            // 手续费金额
                            feeAmt = data.getString("fee_amt");
                            // 技术服务费金额
                            invoiceAmt = data.getString("invoice_amt");

                            // 记录手续费
                            orderSettleBillVo.setFeeAmt(new BigDecimal(feeAmt).add(new BigDecimal(invoiceAmt)));
                            if ("S".equals(transStat)) {
                                orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.SUCCESS.getValue());
                            } else if ("P".equals(transStat)) {
                                orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.PROCESSING.getValue());
                            } else if ("F".equals(transStat)) {
                                orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.FAIL.getValue());
                                orderSettleBillVo.setTradeFailReason(JSON.toJSONString(data));
                            } else {
                                orderSettleBillVo.setTradeFailReason(JSON.toJSONString(data));
                            }

                            TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());

                            try {
                                // 在提现时必须要做查单处理
                                // 更新订单结算记录状态
                                int update = orderSettleBillMapper.updateOrderSettleBill(orderSettleBillVo);
                                if (update == 0) {
                                    log.error("更新订单结算商户补贴支付流水记录状态失败，orderSettleBillId：{}", orderSettleBillVo.getId());
                                    Throw.isBusinessException("更新订单结算商户补贴支付流水记录状态失败");
                                }

                                // 如果补贴转账成功，需要扣除商家的补贴金账户余额和增加商家补贴金流水（两条，一条是补贴扣除，一条是营销补贴服务费）
                                if (OrderSettleBillTradeStateEnum.SUCCESS.getValue().equals(orderSettleBillVo.getTradeState())) {
                                    BusinessSubSubsidyAmtDto businessSubSubsidyAmtDto = new BusinessSubSubsidyAmtDto();
                                    BeanUtils.copyProperties(orderSettleBillVo, businessSubSubsidyAmtDto);
                                    // 扣除商家的补贴金账户余额，增加商家补贴金流水（两条，一条是补贴扣除，一条是营销补贴服务费）
                                    Boolean subSubsidyAmtState = businessApi.subSubsidyAmt(businessSubSubsidyAmtDto).unpack();
                                    if (!subSubsidyAmtState) {
                                        log.error("扣除商家补贴金账户余额失败，orderSettleBillId：{}", orderSettleBillVo.getId());
                                        Throw.isBusinessException("扣除商家补贴金账户余额失败");
                                    }
                                }

                                transactionManager.commit(transaction);
                            } catch (Exception e) {
                                //回滚事务
                                transactionManager.rollback(transaction);
                                log.error("<transactAmt给商户转补贴>事务异常回滚", e);
                                return false;
                            }
                        }
                    } else {
                        // 在提现时必须要做查单处理
                        int update = orderSettleBillMapper.updateOrderSettleBill(orderSettleBillVo);
                        if (update == 0) {
                            log.error("更新订单结算商户补贴支付流水记录状态失败，orderSettleBillId：{}", orderSettleBillVo.getId());
                            return false;
                        }
                    }

                    return true;
                }
            }

            // 调用定制补贴转账接口（给商户分补贴）
            hfTradeMarketPay = new HfTradeMarketPay();
            hfTradeMarketPay.setReqDate(orderSettleBillVo.getReqDate());
            hfTradeMarketPay.setReqSeqId(orderSettleBillVo.getReqSeqId());
            hfTradeMarketPay.setInHfId(orderSettleBillVo.getInHfId());
            hfTradeMarketPay.setInHfAcctId(orderSettleBillVo.getInHfAcctId());
            hfTradeMarketPay.setOutHfId(orderSettleBillVo.getOutHfId());
            hfTradeMarketPay.setTransAmt(orderSettleBillVo.getReceiveAmt().toString());
            JSONObject jsonObject = hfApi.tradeMarketTransferPay(hfTradeMarketPay).unpack();
            if (jsonObject != null) {
                JSONObject data = jsonObject.getJSONObject("data");
                // 交易状态 P:处理中；S：成功；F：失败
                String transStat = data.getString("trans_stat");
                // 手续费金额
                String feeAmt = data.getString("fee_amt");
                // 技术服务费金额
                String invoiceAmt = data.getString("invoice_amt");

                // 记录手续费
                if ("S".equals(transStat)) {
                    orderSettleBillVo.setFeeAmt(new BigDecimal(feeAmt).add(new BigDecimal(invoiceAmt)));
                    orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.SUCCESS.getValue());
                } else if ("P".equals(transStat)) {
                    orderSettleBillVo.setFeeAmt(new BigDecimal(feeAmt).add(new BigDecimal(invoiceAmt)));
                    orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.PROCESSING.getValue());
                } else if ("F".equals(transStat)) {
                    orderSettleBillVo.setFeeAmt(new BigDecimal(feeAmt).add(new BigDecimal(invoiceAmt)));
                    orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.FAIL.getValue());
                    orderSettleBillVo.setTradeFailReason(JSON.toJSONString(data));
                } else {
                    orderSettleBillVo.setTradeFailReason(JSON.toJSONString(data));
                }

                TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());

                try {
                    // 在提现时必须要做查单处理
                    // 更新订单结算记录状态
                    int update = orderSettleBillMapper.updateOrderSettleBill(orderSettleBillVo);
                    if (update == 0) {
                        log.error("更新订单结算商户补贴支付流水记录状态失败，orderSettleBillId：{}", orderSettleBillVo.getId());
                        Throw.isBusinessException("更新订单结算商户补贴支付流水记录状态失败");
                    }

                    // 如果补贴转账成功，需要扣除商家的补贴金账户余额和增加商家补贴金流水（两条，一条是补贴扣除，一条是营销补贴服务费）
                    if (OrderSettleBillTradeStateEnum.SUCCESS.getValue().equals(orderSettleBillVo.getTradeState())) {
                        BusinessSubSubsidyAmtDto businessSubSubsidyAmtDto = new BusinessSubSubsidyAmtDto();
                        BeanUtils.copyProperties(orderSettleBillVo, businessSubSubsidyAmtDto);
                        // 扣除商家的补贴金账户余额，增加商家补贴金流水（两条，一条是补贴扣除，一条是营销补贴服务费）
                        Boolean subSubsidyAmtState = businessApi.subSubsidyAmt(businessSubSubsidyAmtDto).unpack();
                        if (!subSubsidyAmtState) {
                            log.error("扣除商家补贴金账户余额失败，orderSettleBillId：{}", orderSettleBillVo.getId());
                            Throw.isBusinessException("扣除商家补贴金账户余额失败");
                        }
                    }

                    transactionManager.commit(transaction);
                } catch (Exception e) {
                    //回滚事务
                    transactionManager.rollback(transaction);
                    log.error("<transactAmt给商户转补贴>事务异常回滚", e);
                    return false;
                }
            }

            return true;
        } finally {
            LockUtils.unlock(lockKey);
        }
    }

    /**
     * 【汇付转账】商家补贴金转给商户
     * 这里就仅仅根据 orderSettleBillVo 进行转账操作
     */
    @Override
    public Boolean transfer(OrderSettleBillVo orderSettleBillVo) {
        Long id = orderSettleBillVo.getId();
        String logPrefix = "[merchant subsidy transfer]";

        if (orderSettleBillVo.getInHfId() == null) {
            log.error(logPrefix + "汇付余额转账失败，入款账号为空, {}", orderSettleBillVo);
            return false;
        }

        String lockKey = MessageFormat.format(Constant.LOCK_FORMAT, "transferMerchantSubsidyAmt:" + id);
        try {
            LockUtils.blockLock(lockKey, Constant.AUTO_UNLOCK_SECOND);

            TbOrderSettleBillPo tbOrderSettleBillPo = orderSettleBillMapper.selectById(id);
            if (OrderSettleBillTradeStateEnum.SUCCESS.getValue().equals(tbOrderSettleBillPo.getTradeState())) {
                log.info(logPrefix + "订单结算商品补贴已处理成功，orderSettleBillId：{}", id);
                return true;
            }

            LocalDateTime nowLocalDateTime = LocalDateUtil.getNowLocalDateTime();
            String yyyyMMdd = LocalDateUtil.toLocalDateToString(nowLocalDateTime.toLocalDate(), "yyyyMMdd");
            String reqSeqId = LocalDateUtil.toLocalDateTimeToString(nowLocalDateTime, "yyyyMMddHHmmss") + GenerateUtil.getRandomNum(5);

            HfTradeMarketPay hfTradeMarketPay = new HfTradeMarketPay();
            hfTradeMarketPay.setReqDate(yyyyMMdd);
            hfTradeMarketPay.setReqSeqId(reqSeqId);
            hfTradeMarketPay.setOrgReqDate(tbOrderSettleBillPo.getReqDate());
            hfTradeMarketPay.setOrgReqSeqId(tbOrderSettleBillPo.getReqSeqId());
            // 先查询汇付交易记录
            JSONObject queryJSONObject = hfApi.tradeMarketTransferQuery(hfTradeMarketPay).unpack();

            if (queryJSONObject != null) {
                JSONObject data = queryJSONObject.getJSONObject("data");
                String respCode = data.getString("resp_code");
                // 交易状态 P:处理中；S：成功；F：失败
                String transStat = data.getString("trans_status");
                if ("00000000".equals(respCode)) {
                    // 如果是失败，则请求日期和请求流水号需要用最新的，先更新到数据库，下面再用新的去请求汇付接口
                    if ("F".equals(transStat)) {
                        orderSettleBillVo.setReqDate(yyyyMMdd);
                        orderSettleBillVo.setReqSeqId(reqSeqId);
                        orderSettleBillVo.setTradeFailReason(JSON.toJSONString(data));
                    }
                    // 如果是成功，返回成功
                    if ("S".equals(transStat)) {
                        orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.SUCCESS.getValue());
                    }
                    int update = orderSettleBillMapper.updateOrderSettleBill(orderSettleBillVo);
                    if (update == 0) {
                        log.error(logPrefix + "商户补贴余额支付查单更新请求流水号失败，orderSettleBillId：{}", orderSettleBillVo.getId());
                        return false;
                    }
                    // 如果是交易成功，直接返回成功
                    if ("S".equals(transStat)) {
                        return true;
                    }
                    // 如果是处理中，直接返回失败，这样子业务方可以当成交易失败，从而进行重试
                    if ("P".equals(transStat)) {
                        return false;
                    }
                }
            }

            hfTradeMarketPay = new HfTradeMarketPay();
            hfTradeMarketPay.setReqDate(orderSettleBillVo.getReqDate());
            hfTradeMarketPay.setReqSeqId(orderSettleBillVo.getReqSeqId());
            hfTradeMarketPay.setInHfId(orderSettleBillVo.getInHfId());
            hfTradeMarketPay.setInHfAcctId(orderSettleBillVo.getInHfAcctId());
            hfTradeMarketPay.setOutHfId(orderSettleBillVo.getOutHfId());
            hfTradeMarketPay.setTransAmt(orderSettleBillVo.getReceiveAmt().toString());
            JSONObject jsonObject = hfApi.tradeMarketTransferPay(hfTradeMarketPay).unpack();
            if (jsonObject == null) {
                return false;
            }

            JSONObject data = jsonObject.getJSONObject("data");
            // 交易状态 P:处理中；S：成功；F：失败
            String transStat = data.getString("trans_stat");
            // 手续费金额
            String feeAmt = data.getString("fee_amt");
            // 技术服务费金额
            String invoiceAmt = data.getString("invoice_amt");
            BigDecimal totalFeeAmt = (new BigDecimal(feeAmt).add(new BigDecimal(invoiceAmt)));

            if (!orderSettleBillVo.getFeeAmt().equals(totalFeeAmt)) {
                log.error(logPrefix + "商户补贴总手续费平台计算跟汇付计算有差异：orderSettleId: {}, 平台：{}, 汇付：{}", id, orderSettleBillVo.getFeeAmt(), totalFeeAmt);
            }
            orderSettleBillVo.setFeeAmt(totalFeeAmt);

            if ("S".equals(transStat)) {
                orderSettleBillVo.setTradeState(OrderSettleBillTradeStateEnum.SUCCESS.getValue());
            }
            // 如果不是 P:处理中，S:成功，则记录一下失败原因
            if (!("P".equals(transStat)) && !("S".equals(transStat))) {
                orderSettleBillVo.setTradeFailReason(JSON.toJSONString(data));
            }
            int update = orderSettleBillMapper.updateOrderSettleBill(orderSettleBillVo);
            if (update == 0) {
                log.error(logPrefix + "商户补贴余额支付查单更新失败，orderSettleBillId：{}", orderSettleBillVo.getId());
                return false;
            }

            if ("S".equals(transStat)) {
                return true;
            }
        } finally {
            LockUtils.unlock(lockKey);
        }

        return false;
    }
}
